home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
gnu
/
gawk
/
gawk213b.zoo
/
test
/
lisp
/
walk
< prev
next >
Wrap
Text File
|
1991-05-21
|
14KB
|
691 lines
#!/bin/awk -f
#
# walk -- LISP in awk
#
# An interpreter for LISP, written in awk(1).
# Copyright (c) 1988, 1990 Roger Rohrbach
BEGIN {
# interpreter constants:
stdin = "-";
true = 1;
false = 0;
constant = "#"; # flags literal atoms
alist = -10000; # head of bound variable list
# global variables:
atom = -1; # atoms are allocated down from -1
cell = 1; # list cells are allocated up from 1
environment = alist; # pointer to current evaluation context;
# saved in context[] before evaluating body
# of lambda expression, restored afterwards
# LISP constants:
nil = intern["nil"] = atom--; # intern[x] is the LISP atom named by x
name[nil] = "()"; # name[s] is the print name of atom s
value[nil] = constant; # if x < alist, value[x] is the local
# binding of the atom `symbol[x]'; otherwise
# it is the top-level binding of the atom x.
t = intern["t"] = atom--;
name[t] = "t";
value[t] = constant;
lambda = intern["lambda"] = atom--;
name[lambda] = "lambda";
value[lambda] = constant;
# install the intrinsic functions:
split("cons cdr car eq atom set eval error quote cond and or list", \
intrinsics);
for (i in intrinsics)
{
id = intrinsics[i];
intern[id] = atom--;
name[intern[id]] = id;
value[intern[id]] = sprintf("@%d", i);
name[value[intern[id]]] = sprintf("<intrinsic #%d>", i);
}
# these constants speed things up a bit
CONS = value[intern["cons"]];
CDR = value[intern["cdr"]];
CAR = value[intern["car"]];
EQ = value[intern["eq"]];
ATOM = value[intern["atom"]];
SET = value[intern["set"]];
EVAL = value[intern["eval"]];
ERROR = value[intern["error"]];
QUOTE = value[intern["quote"]];
COND = value[intern["cond"]];
AND = value[intern["and"]];
OR = value[intern["or"]];
LIST = value[intern["list"]];
# messages:
TYPE_ERROR = "invalid argument to %s: %s\n";
REDEF_ERROR = "can't redefine intrinsic function %s\n";
UNDEF_ERROR = "undefined function: %s\n";
HELLO = "walk (LISP in awk)\tCopyright (c) 1988, 1990 Roger Rohrbach\n";
GOODBYE = "%d atoms, %d list cells.\n";
# interpreter is ready
if (FILENAME == stdin)
{
print HELLO;
printf("-> ");
}
}
# interpreter loop:
{
pos = 0; # current input character position
eol = length + 1; # read past last char for endquote, below
while (++pos <= eol)
{
#########
# read #
#########
if (endquote)
{
# close a quoted expr by inserting a right parenthesis
endquote = false;
c = ")";
--pos; # if at eol, c is null; push back on input
}
else
c = substr($0, pos, 1);
if (c == " " || c == "\t")
continue;
else if (c == "" || c == ";")
{
# eol or comment
break;
}
else if (c == "'")
{
# expand 's to (quote s)
if (level > 0 && level != rp)
read[++rp] = CONS;
read[++rp] = CONS;
quotes[++qp] = ++level;
read[++rp] = intern["quote"];
}
else if (c == "\"")
{
string = true;
}
else if (c == "(")
{
# begin a list
read[++rp] = CONS;
++level;
}
else if (c == ")")
{
if (level == 0)
{
printf("ignored extra right parenthesis\n");
continue;
}
else if (rp == level && read[rp] == CONS)
--rp; # empty list read in
# have just read a list
read[++rp] = nil;
--level;
if (qp > 0 && quotes[qp] == level)
{
# finish quoting this list
--qp;
endquote = true;
}
# actually construct the list
while (read[rp - 2] == CONS && read[rp - 1] != CONS)
{
cdr[cell] = read[rp];
car[cell] = read[--rp];
read[--rp] = cell++;
}
}
else if (c ~ /[0-9]/)
{
# read a number (integer)
n = c;
while ((c = substr($0, ++pos, 1)) ~ /[0-9]/)
n = n c;
--pos;
if (level > 0 && level != rp)
read[++rp] = CONS;
if (!intern[n])
{
intern[n] = atom--;
name[intern[n]] = n;
value[intern[n]] = constant;
}
read[++rp] = intern[n];
if (qp > 0 && quotes[qp] == level)
{
--qp;
endquote = true;
}
}
else if (c ~ /[_A-Za-z]/ || string)
{
# read an identifier
id = c;
if (string)
{
while ((c = substr($0, ++pos, 1)) != "\"")
id = id c;
string = false;
}
else
{
while ((c = substr($0, ++pos, 1)) ~ /[-A-Za-z_0-9]/)
id = id c;
--pos;
}
if (level > 0 && level != rp)
read[++rp] = CONS;
if (!intern[id])
{
intern[id] = atom--;
name[intern[id]] = id;
value[intern[id]] = nil;
}
read[++rp] = intern[id];
if (qp > 0 && quotes[qp] == level)
{
--qp;
endquote = true;
}
}
else if (c == "%")
{
# refer to objects by `address'
lispval = "";
while ((c = substr($0, ++pos, 1)) ~ /[-0-9]/)
lispval = lispval c;
if (!length(lispval))
lispval = nil;
--pos;
if (level > 0 && level != rp)
read[++rp] = CONS;
read[++rp] = lispval;
if (qp > 0 && quotes[qp] == level)
{
--qp;
endquote = true;
}
}
else
printf("illegal character: %s\n", c);
if (rp && level == 0) # have read an s-expression
{
#########
# eval #
#########
eval[++ep] = read[rp--];
while (ep > 0)
{
s = eval[ep];
if (s < 0)
{
# atomic s-expression
if (s == lambda && fp)
{
environment = context[fp--]; # restore environment
}
else if (value[s] == constant)
arg[++ap] = s;
else
{
# look up value of s in environment:
bound = false;
for (i = environment; i < alist; ++i)
{
if (symbol[i] == s)
{
bound = true;
break;
}
}
if (bound)
arg[++ap] = value[i];
else # use value cell
arg[++ap] = value[s];
}
--ep;
}
else if (index(s, "@"))
{
# intrinsic function application:
if (s == CONS)
{
car[cell] = arg[ap];
cdr[cell] = arg[--ap];
if (cdr[cell] < 0 && cdr[cell] != nil)
{
printf(TYPE_ERROR, "cons", name[cdr[cell]]);
arg[ap = ep = 1] = nil; # stop evaluation
}
else
arg[ap] = cell++;
}
else if (s == CDR)
{
if (arg[ap] < 0)
{
printf(TYPE_ERROR, "cdr", name[arg[ap]]);
arg[ap = ep = 1] = nil;
}
else
arg[ap] = cdr[arg[ap]];
}
else if (s == CAR)
{
if (arg[ap] < 0)
{
printf(TYPE_ERROR, "car", name[arg[ap]]);
arg[ap = ep = 1] = nil;
}
else
arg[ap] = car[arg[ap]];
}
else if (s == EQ)
{
arg1 = arg[ap];
if (arg[--ap] == arg1)
arg[ap] = t;
else
arg[ap] = nil;
}
else if (s == ATOM)
{
if (arg[ap] < 0)
arg[ap] = t;
else
arg[ap] = nil;
}
else if (s == SET)
{
if ((arg1 = arg[ap]) > 0)
{
printf(TYPE_ERROR, "set", "must be atomic");
arg[ap = ep = 1] = nil;
}
else if (value[arg1] == constant)
{
printf(TYPE_ERROR, "set", name[arg1]);
arg[ap = ep = 1] = nil;
}
else if (index(value[arg1], "@"))
{
printf(REDEF_ERROR, name[arg1]);
arg[ap = ep = 1] = nil;
}
else
{
bound = false;
for (i = environment; i < alist; ++i)
{
if (symbol[i] == arg1)
{
bound = true;
break;
}
}
arg2 = arg[--ap];
if (bound) # replace binding
arg[ap] = value[i] = arg2;
else # set value
arg[ap] = value[arg1] = arg2;
}
}
else if (s == EVAL)
{
eval[ep++] = arg[ap--];
}
else if (s == ERROR)
{
if (arg[ap] > 0)
printf(TYPE_ERROR, "error", "must be atomic");
else
printf("%s\n", n